package com.lamb.script.core.utils;


import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;

/**
 * 支持分库分表的数据源.
 *
 * @author : lamb
 * @version : 1.0
 * @date :  2018-12-06 10:19
 **/
public class MySqlShardDataSource implements DataSource, AutoCloseable {

    /**
     * 配置文件.
     */
    private final Properties config;

    /**
     * 缓存的连接信息.
     */
    private final Map<String, Connection> dataSourceMap = new HashMap<>();

    public MySqlShardDataSource(Properties config) {
        this.config = config;
    }

    /**
     * 获取一个连接.
     *
     * @param dbKey 属性key.
     * @return 连接.
     * @throws SQLException 异常.
     */
    public synchronized Connection getConnection(String dbKey) throws SQLException {
        String[] split = dbKey.split("\\.");
        String env = split[0];
        String instance = split[1];
        Integer instanceNum = null;
        Integer dbIndex = null;
        if (split.length == 3) {
            dbIndex = Integer.valueOf(split[2]) % Integer.valueOf(getPropertyInner(env + "." + instance + ".db.num"));
            instanceNum = dbIndex % Integer.valueOf(getPropertyInner(env + "." + instance + ".instance.num"));
        }

        String datasourceKey = env + "." + instance + instanceNum;
        Connection connection = dataSourceMap.get(datasourceKey);
        if (null == connection) {
            String url = getPropertyInner(env + "." + instance +
                    (null != instanceNum ? instanceNum : "") + ".url");
            String user = getPropertyInner(env + "." + instance + ".user");
            String pwd = getPropertyInner(env + "." + instance + ".pwd");
            DataSource dataSource = null;
            if (url.contains("jdbc:mysql")) {
                try {
                    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
                    Class<?> mysqlDataSourceClass = contextClassLoader
                            .loadClass("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
                    dataSource = (DataSource) mysqlDataSourceClass.newInstance();
                    Method setUrl = mysqlDataSourceClass.getMethod("setUrl", String.class);
                    setUrl.invoke(dataSource, url);
                } catch (Exception e) {
                    throw new SQLException(e);
                }
            }
            if (null == dataSource) {
                throw new RuntimeException("dataSource not config.");
            }
            connection = dataSource.getConnection(user, pwd);
            dataSourceMap.put(datasourceKey, connection);
        }
        if (null != dbIndex) {
            connection.setCatalog(getPropertyInner(env + "." + instance + ".db.name") + dbIndex);
        }
        return connection;
    }

    /**
     * 获取属性.
     *
     * @param key key.
     * @return 属性值.
     */
    private String getPropertyInner(String key) {
        return System.getProperty(key, config.getProperty(key));
    }

    @Override
    public Connection getConnection() throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public void close() {
        for (Connection connection : dataSourceMap.values()) {
            ScriptUtil.closeQuietly(connection);
        }
    }

    @Override
    public int getLoginTimeout() throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
        throw new SQLException("not support!");
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        throw new SQLFeatureNotSupportedException("not support!");
    }
}
